package com.idea.relax.crypto.core;

import com.idea.relax.crypto.annotation.Encrypt;
import com.idea.relax.crypto.config.CryptoType;
import com.idea.relax.crypto.config.RelaxCryptoProperties;
import com.idea.relax.crypto.exception.CryptoException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author: 沉香
 * @date: 2023/3/18
 * @description:
 */
@Slf4j
@Order(1)
@AutoConfiguration
@ControllerAdvice
@AllArgsConstructor
@ConditionalOnProperty(prefix = RelaxCryptoProperties.PREFIX, name = ".enabled", havingValue = "true")
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {

	private final RelaxCryptoProperties properties;


	private final ICryptographerRegister cryptographerRegister;

	@Override
	public boolean supports(MethodParameter returnType, Class converterType) {
		if (!properties.isEnabled()) {
			return false;
		}
		return AnnotatedElementUtil.isAnnotated(returnType, Encrypt.class);
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
		if (body == null) {
			return null;
		}
		response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
		Encrypt encrypt = AnnotatedElementUtil.getAnnotation(returnType, Encrypt.class);
		String privateKey = properties.getPrivateKey();
		String annoPriKey = encrypt.privateKey();
		if (Func.isNotEmpty(annoPriKey)) {
			privateKey = annoPriKey;
		}
		if (Func.isEmpty(privateKey)) {
			throw new CryptoException("Configure a private key!");
		}
		//找出复合条件的ICryptographer加密类
		CryptoType cryptoType = encrypt.cryptoType();
		ICryptographer cryptographer = cryptographerRegister.getIfAbsentThrow(cryptoType);
		byte[] bodyJsonBytes = JsonUtil.toJsonAsBytes(body);
		return cryptographer.encryptToBase64(bodyJsonBytes, privateKey);
	}

}
